""" 分拣模拟系统
"""
import random
import asyncio
import json
import os
from datetime import datetime

# 使用统一的日志配置
from fastapiApp.setting.logger_config import get_simulation_logger
logger = get_simulation_logger()

""" 分拣模拟系统"""
class AgvSortingSimulator:
    """ 初始化分拣模拟系统    """
    def __init__(self):

        self.config = {
            "production_line1_type": [], # 产线1产品类型
            "production_line1_time": [], # 产线1生产时间
            "production_line2_type": [], # 产线2产品类型
            "production_line2_time": [], # 产线2生产时间
            "product_types": [], # 产品类型列表
            "product_colors": {}, # 产品颜色映射
            "product_generation_mode": "random", # 产品生成模式: random(随机) 或 sequence(顺序)
            "product_types_count": 8, # 产品种类数量
            "transfer_station_size": 13, # 中转站库位数量
            "production_line1_size": 24, # 产线1库位数量
            "production_line2_size": 24, # 产线2库位数量
        }

        # 系统状态
        self.state = {
            "production_line1": [],  # 产线1的产品
            "production_line1_countdown": [],  # 产线1AGV倒计时
            "production_line1_finsh_time": [],  # 产线1AGV完成时间
            "production_line2": [],  # 产线2的产品
            "production_line2_countdown": [],  # 产线2AGV倒计时
            "production_line2_finsh_time": [],  # 产线2AGV完成时间
            "production_AGV1": [],  # 产线AGV1产品
            "production_AGV2": [],  # 产线AGV2产品
            "sorting_station": [],  # 分拣台的产品
            "transfer_station": [],  # 中转站的产品
            "sorting_AGV": [],  # 分拣AGV产品
            "flip_station": [],  # 翻转台的产品
            "flip_AGV": [],  # 翻转AGV产品
            "drop_rack": [],  # 落丝架的产品

            "is_auto_running": True,  # 是否自动运行
            "sequence_index": 0,  # 顺序生成的当前索引
            "out_product_list": [],  # 出库产品
        }

        self.tasklist = []

        print(self.config)

    """ 启动分拣模拟系统 """
    async def start_simulation(self) -> None:
        logger.info("id_003 启动分拣模拟系统")
        self.state["is_auto_running"] = True
        await self.generate_product_timer()  # 生成产品定时器

    """ 停止分拣模拟系统 """
    async def stop_simulation(self) -> None:
        logger.info("id_004 停止分拣模拟系统 所有task取消")
        self.state["is_auto_running"] = False
        # 重置所有任务
        for task in self.tasklist:
            task.cancel()
        self.tasklist.clear()

    """ 初始化模拟系统    """
    async def init_simulation(self) -> None:
        # 初始化产品类型列表
        self.config["product_types"] = [
            f"P{i+1}" for i in range(self.config["product_types_count"])]
        # 初始化产品颜色映射
        for i in range(self.config["product_types_count"]):
            label = self.config["product_types"][i]
            # 生成独特的颜色
            hue = (i * (360 / self.config["product_types_count"])) % 360
            self.config["product_colors"][label] = f"hsl({hue}, 70%, 50%)"

        # 初始化产线1
        self.state["production_line1"] = [None] * self.config["production_line1_size"]
        self.config["production_line1_time"] = []
        self.state["production_line1_countdown"] = []
        self.config["production_line1_type"] = []
        self.state["production_line1_finsh_time"] = []

        # 初始化产线2
        self.state["production_line2"] = [None] * self.config["production_line2_size"]
        self.config["production_line2_time"] = []
        self.state["production_line2_countdown"] = []
        self.config["production_line2_type"] = []
        self.state["production_line2_finsh_time"] = []

        for i in range(self.config["production_line1_size"]):
            time  = 10 if i < 8 else i * 8 + 20
            self.config["production_line1_time"].append(time)  # 随机选择时间间隔
            self.state["production_line1_countdown"].append(time)  # 初始化倒计时
            self.state["production_line1_finsh_time"].append(0)  # 初始化完成时间
            self.config["production_line1_type"].append(
                self.config["product_types"][i % self.config["product_types_count"]])  # 初始化产品种类

        for i in range(self.config["production_line2_size"]):
            time  = i * 8 + 10
            self.config["production_line2_time"].append(time)  # 随机选择时间间隔
            self.state["production_line2_countdown"].append(time)  # 初始化倒计时
            self.state["production_line2_finsh_time"].append(0)  # 初始化完成时间
            self.config["production_line2_type"].append(
                self.config["product_types"][i % self.config["product_types_count"]])  # 初始化产品种类

        # 初始化产线AGV1产品
        self.state["production_AGV1"] = []
        # 初始化产线AGV2产品
        self.state["production_AGV2"] = []
        # 初始化分拣台的产品
        self.state["sorting_station"] = []
        # 初始化中转站的产品
        self.state["transfer_station"] = [None] * self.config["transfer_station_size"]
        self.state["sorting_AGV"] = []
        self.state["flip_station"] = []
        self.state["flip_AGV"] = []
        # 初始化落丝架的产品
        self.state["drop_rack"] = [
            [None for _ in range(3)] for _ in range(self.config["product_types_count"])]

        self.state["out_product_list"] = []  # 出库产品

        self.save_data()

    """ 定时taskr任务生成 """
    async def generate_product_timer(self) -> None:
        logger.info("id_005 定时task任务生成")

        self.tasklist.append(asyncio.create_task(self.creat_production()))
        self.tasklist.append(asyncio.create_task(self.manual_drop_rack_product()))
        self.tasklist.append(asyncio.create_task(self.production_AGV_receive_product()))
        self.tasklist.append(asyncio.create_task(self.sorting_station_receive_product()))
        self.tasklist.append(asyncio.create_task(self.sorting_AGV_receive_product()))
        self.tasklist.append(asyncio.create_task(self.drop_rack_receive_product()))
        self.tasklist.append(asyncio.create_task(self.flip_AGV_receive_product()))
        self.tasklist.append(asyncio.create_task(self.sorting_AGV_sort_product()))
        self.tasklist.append(asyncio.create_task(self.countdown_timer()))

    """ 计时任务 """
    async def countdown_timer(self) -> None:
        # 计数器，用于定期保存状态
        save_counter = 0
        save_interval = 10  # 每10秒保存一次状态

        while True:
            if not self.state["is_auto_running"]:
                await asyncio.sleep(1)
                continue

            # 检查产线1AGV倒计时
            for i in range(self.config["production_line1_size"]):
                if self.state["production_line1_countdown"][i] > -999:
                    self.state["production_line1_countdown"][i] -= 1
                else:
                    # 倒计时结束，重置倒计时
                    self.state["production_line1_countdown"][i] = -999
                if self.state["production_line1"][i] is not None:
                    self.state["production_line1_finsh_time"][i] += 1
            # 检查产线2AGV倒计时
            for i in range(self.config["production_line2_size"]):
                if self.state["production_line2_countdown"][i] > -999:
                    self.state["production_line2_countdown"][i] -= 1
                else:
                    # 倒计时结束，重置倒计时
                    self.state["production_line2_countdown"][i] = -999
                if self.state["production_line2"][i] is not None:
                    self.state["production_line2_finsh_time"][i] += 1

            # 定期保存状态
            save_counter += 1
            if save_counter >= save_interval:
                save_counter = 0
                self.save_data()

            await asyncio.sleep(1)

    """ 生成产品 """
    async def creat_production(self):
        while True:
            if not self.state["is_auto_running"]:
                await asyncio.sleep(1)
                continue
            # 检查产线1是否有产品
            for i, time in enumerate(self.state["production_line1_countdown"]):
                if time < 0 and self.state["production_line1"][i] is None:
                    self.state["production_line1"][i] = self.config["production_line1_type"][i]
                    self.state["production_line1_countdown"][i] = self.config["production_line1_time"][i]
                    self.state["production_line1_finsh_time"][i] = 0
                    logger.info(f"id_006 None -> 产线1 {i} , 产品: {self.config['production_line1_type'][i]}")
            # 检查产线2是否有产品
            for i, time in enumerate(self.state["production_line2_countdown"]):
                if time < 0 and self.state["production_line2"][i] is None:
                    self.state["production_line2"][i] = self.config["production_line2_type"][i]
                    self.state["production_line2_countdown"][i] = self.config["production_line2_time"][i]
                    self.state["production_line2_finsh_time"][i] = 0
                    logger.info(f"id_007 None -> 产线2 {i} , 产品: {self.config['production_line2_type'][i]}")

            await asyncio.sleep(1)

    """ 人工转运落丝架产品 """
    async def manual_drop_rack_product(self) -> None:
        # 检查落丝架是否有产品
        while True:
            if not self.state["is_auto_running"]:
                await asyncio.sleep(1)
                continue

            for i in range(self.config["product_types_count"]):
                if self.state["drop_rack"][i][0] != None:
                    if self.state["drop_rack"][i][1] != None:
                        if self.state["drop_rack"][i][2] != None:
                            await asyncio.sleep(8)
                            logger.info(f"id_008 人工转运落丝架 P{i + 1} , 出库成功")
                            self.state["out_product_list"].append(self.state["drop_rack"][i][0])
                            for j in range(3):
                                self.state["drop_rack"][i][j] = None

            await asyncio.sleep(1)

    """ 产线AGV接收产品 """
    async def production_AGV_receive_product(self) -> None:
        while True:
            if not self.state["is_auto_running"]:
                await asyncio.sleep(1)
                continue

            # 检查产线AGV是否有空位
            if len(self.state["production_AGV1"]) < 3:
                await asyncio.sleep(1)
                # 倒计时最小的产品先取出
                min_countdown = self.state["production_line1_finsh_time"].index(max(self.state["production_line1_finsh_time"]))
                for i, product in enumerate(self.state["production_line1"]):
                    if product != None and i == min_countdown:
                        self.state["production_AGV1"].append(product)
                        self.state["production_line1"][i] = None
                        logger.info(f"id_009 产线1 {i} -> 产线AGV1 {len(self.state['production_AGV1']) - 1 } , 产品: {product}")
                        break

            # 检查产线2AGV是否有空位
            if len(self.state["production_AGV2"]) < 3:
                await asyncio.sleep(1)
                # 倒计时最小的产品先取出
                min_countdown = self.state["production_line2_finsh_time"].index(max(self.state["production_line2_finsh_time"]))
                for i, product in enumerate(self.state["production_line2"]):
                    if product != None and i == min_countdown:
                        self.state["production_AGV2"].append(product)
                        self.state["production_line2"][i] = None
                        logger.info(f"id_010 产线2 {i} -> 产线AGV2 {len(self.state['production_AGV2']) - 1 } , 产品: {product}")
                        break

            await asyncio.sleep(1)

    """ 分拣台接收产品 """
    async def sorting_station_receive_product(self) -> None:
        # 设置分拣台AGV接收产品的优先级,轮流接收产线1AGV和产线2AGV的产品
        priority = 0
        wait_count = 0
        while True:
            if not self.state["is_auto_running"]:
                await asyncio.sleep(1)
                continue
            if priority == 0:
                # 检查分拣台是否有空位 且 产线AGV1产品是否已满
                if len(self.state["sorting_station"]) == 0 and len(self.state["production_AGV1"]) == 3:
                    await asyncio.sleep(3)  # 等待3秒,
                    for i, product in enumerate(self.state["production_AGV1"]):
                        self.state["sorting_station"].append(product)
                        self.state["production_AGV1"][i] = None
                    self.state["production_AGV1"] = []
                    logger.info(f"id_011 产线AGV1 all -> 分拣台 , 产品: {self.state['sorting_station'][0]}")
                    priority = 1
                    wait_count = 0
                    await asyncio.sleep(3)  # 等待7秒, 防止产线AGV2产品立即进入分拣台

                else:
                    wait_count += 1
                    if wait_count >= 5:
                        priority = 1
                        wait_count = 0
                    await asyncio.sleep(1)


            if priority == 1:
                # 检查分拣台是否有空位 且 产线AGV2产品是否已满
                if len(self.state["sorting_station"]) == 0 and len(self.state["production_AGV2"]) == 3:
                    await asyncio.sleep(3)  # 等待3秒,
                    for i, product in enumerate(self.state["production_AGV2"]):
                        self.state["sorting_station"].append(product)
                        self.state["production_AGV2"][i] = None
                    self.state["production_AGV2"] = []
                    logger.info(f"id_012 产线AGV2 all -> 分拣台 , 产品: {self.state['sorting_station'][0]}")
                    priority = 0
                    wait_count = 0
                    await asyncio.sleep(3)  # 等待7秒, 防止产线AGV1产品立即进入分拣台

                else:
                    wait_count += 1
                    if wait_count >= 5:
                        priority = 0
                        wait_count = 0
                    await asyncio.sleep(1)

    """ 分拣AGV接收产品 """
    async def sorting_AGV_receive_product(self) -> None:
        while True:
            if not self.state["is_auto_running"]:
                await asyncio.sleep(1)
                continue

            # 检查是否满足相同产品 转运至中继站
            # 先接一个 后面的由分拣函数完成
            is_transfer, index = self.check_transfer_station()
            if is_transfer and len(self.state["sorting_AGV"]) == 0:
                await asyncio.sleep(1)
                self.state["sorting_AGV"].append(self.state["transfer_station"][index])
                self.state["sorting_AGV"].append(None)
                self.state["sorting_AGV"].append(None)
                self.state["transfer_station"][index] = None
                logger.info(f"id_013 分拣台 {index} -> 分拣AGV 0 , 产品: {self.state['sorting_AGV'][0]}")

            # 检查分拣台是否有产品
            if len(self.state["sorting_station"]) == 3 and len(self.state["sorting_AGV"]) == 0:
                await asyncio.sleep(1)
                for i, product in enumerate(self.state["sorting_station"]):
                    self.state["sorting_AGV"].append(product)
                    self.state["sorting_station"][i] = None
                self.state["sorting_station"] = []
                logger.info(f"id_014 分拣台 all -> 分拣AGV , 产品: {self.state['sorting_AGV'][0]}")
                await asyncio.sleep(3)

            await asyncio.sleep(1)

    """ 中继AGV接收产品 """
    async def flip_AGV_receive_product(self) -> None:
        while True:
            if not self.state["is_auto_running"]:
                await asyncio.sleep(1)
                continue
            # 检查翻转台是否有产品
            if len(self.state["flip_station"]) == 3 and self.state["flip_AGV"] == []:
                await asyncio.sleep(1)
                for i, product in enumerate(self.state["flip_station"]):
                    self.state["flip_AGV"].append(product)
                    self.state["flip_station"][i] = None
                self.state["flip_station"] = []
                logger.info(f"id_015 翻转台 all -> 中继AGV , 产品: {self.state['flip_AGV'][0]}")
                await asyncio.sleep(2)

            await asyncio.sleep(1)

    """ 挂丝车接收产品 """
    async def drop_rack_receive_product(self) -> None:
        while True:
            if not self.state["is_auto_running"]:
                await asyncio.sleep(1)
                continue

            # 检查挂丝车是否有产品
            if len(self.state["flip_AGV"]) == 3:
                await asyncio.sleep(1)
                product = self.state["flip_AGV"][0]
                match product:
                    case "P1":
                        if self.state["drop_rack"][0] == [None, None, None]:
                            self.state["drop_rack"][0] = self.state["flip_AGV"]
                            self.state["flip_AGV"] = []
                            logger.info(f"id_016 中继AGV all -> 挂丝车 P1 , 产品: {product}")
                        else:
                            logger.error(f"id_017 挂丝车 P1 已存在产品 {self.state['drop_rack'][0]} 未及时转运")
                            await asyncio.sleep(5)
                    case "P2":
                        if self.state["drop_rack"][1] == [None, None, None]:
                            self.state["drop_rack"][1] = self.state["flip_AGV"]
                            self.state["flip_AGV"] = []
                            logger.info(f"id_018 中继AGV all -> 挂丝车 P2 , 产品: {product}")
                        else:
                            logger.error(f"id_019 挂丝车 P2 已存在产品 {self.state['drop_rack'][1]} 未及时转运")
                            await asyncio.sleep(5)
                    case "P3":
                        if self.state["drop_rack"][2] == [None, None, None]:
                            self.state["drop_rack"][2] = self.state["flip_AGV"]
                            self.state["flip_AGV"] = []
                            logger.info(f"id_020 中继AGV all -> 挂丝车 P3 , 产品: {product}")
                        else:
                            logger.error(f"id_021 挂丝车 P3 已存在产品 {self.state['drop_rack'][2]} 未及时转运")
                            await asyncio.sleep(5)
                    case "P4":
                        if self.state["drop_rack"][3] == [None, None, None]:
                            self.state["drop_rack"][3] = self.state["flip_AGV"]
                            self.state["flip_AGV"] = []
                            logger.info(f"id_022 中继AGV all -> 挂丝车 P4 , 产品: {product}")
                        else:
                            logger.error(f"id_023 挂丝车 P4 已存在产品 {self.state['drop_rack'][3]} 未及时转运")
                            await asyncio.sleep(5)
                    case "P5":
                        if self.state["drop_rack"][4] == [None, None, None]:
                            self.state["drop_rack"][4] = self.state["flip_AGV"]
                            self.state["flip_AGV"] = []
                            logger.info(f"id_024 中继AGV all -> 挂丝车 P5 , 产品: {product}")
                        else:
                            logger.error(f"id_025 挂丝车 P5 已存在产品 {self.state['drop_rack'][4]} 未及时转运")
                            await asyncio.sleep(5)
                    case "P6":
                        if self.state["drop_rack"][5] == [None, None, None]:
                            self.state["drop_rack"][5] = self.state["flip_AGV"]
                            self.state["flip_AGV"] = []
                            logger.info(f"id_026 中继AGV all -> 挂丝车 P6 , 产品: {product}")
                        else:
                            logger.error(f"id_027 挂丝车 P6 已存在产品 {self.state['drop_rack'][5]} 未及时转运")
                            await asyncio.sleep(5)
                    case "P7":
                        if self.state["drop_rack"][6] == [None, None, None]:
                            self.state["drop_rack"][6] = self.state["flip_AGV"]
                            self.state["flip_AGV"] = []
                            logger.info(f"id_028 中继AGV all -> 挂丝车 P7 , 产品: {product}")
                        else:
                            logger.error(f"id_029 挂丝车 P7 已存在产品 {self.state['drop_rack'][6]} 未及时转运")
                            await asyncio.sleep(5)
                    case "P8":
                        if self.state["drop_rack"][7] == [None, None, None]:
                            self.state["drop_rack"][7] = self.state["flip_AGV"]
                            self.state["flip_AGV"] = []
                            logger.info(f"id_031 中继AGV all -> 挂丝车 P8 , 产品: {product}")
                        else:
                            logger.error(f"id_031 挂丝车 P8 已存在产品 {self.state['drop_rack'][7]} 未及时转运")
                            await asyncio.sleep(5)
                    case _:
                        logger.error(f"id_032 异常 存在未知产品 {product}")
                        await asyncio.sleep(5)

            await asyncio.sleep(1)

    """ 分拣AGV 分拣动作 """
    async def sorting_AGV_sort_product(self) -> None:
        while True:
            if not self.state["is_auto_running"]:
                await asyncio.sleep(1)
                continue

            # 检查是否所有产品已分拣完成
            if self.state["sorting_AGV"] == [None, None, None]:
                await asyncio.sleep(1)
                self.state["sorting_AGV"] = []
                logger.info(f"id_033 分拣完成 ")
                continue

            # 检查分拣AGV是否空车 空车则等待
            if self.state["sorting_AGV"] == []:
                await asyncio.sleep(1)
                continue

            # 检查是否满足相同产品 转运至翻转台
            ready_to_flip = self.state["sorting_AGV"][0] == self.state["sorting_AGV"][1] and self.state["sorting_AGV"][1] == self.state["sorting_AGV"][2]
            if ready_to_flip and self.state["flip_station"] == []:
                await asyncio.sleep(1)
                for i, product in enumerate(self.state["sorting_AGV"]):
                    self.state["flip_station"].append(product)
                    self.state["sorting_AGV"][i] = None
                logger.info(f"id_043 分拣AGV all -> 翻转台 all , 产品: {product}")
                continue

            await self.sort_products()

    """分拣产品"""
    async def sort_products(self):
        # 优先转运产品
        await asyncio.sleep(1)
        out_product = None
        for i, product in enumerate(self.state["sorting_AGV"]):
            # 如果产品已在AGV中 跳过本次循环 不动作
            if self.check_all_station(product) or self.check_sorting_and_transfer(product):
                # 如果满足转运 先赋值 第二次循环 检查是否为相同产品 是的话也跳过
                if product == out_product:
                    continue
                if out_product is None:
                    out_product = product

            # 如果位置为空 跳过本次循环 不动作
            if product is None:
                if self.state["transfer_station"].count(None) == 0:
                    flag = 0
                    for j, cell in enumerate(self.state["transfer_station"]):
                        if self.check_all_station(cell) and out_product is None:
                            self.state["sorting_AGV"][i] = cell
                            self.state["transfer_station"][j] = None
                            logger.info(f"id_001 中转站 {j} -> 分拣AGV {i} , 产品: {cell}")
                            flag = 1
                            return
                        if self.check_all_station(cell) and out_product == cell:
                            self.state["sorting_AGV"][i] = cell
                            self.state["transfer_station"][j] = None
                            logger.info(f"id_001 中转站 {j} -> 分拣AGV {i} , 产品: {cell}")
                            flag = 1
                            return
                    if flag == 0:
                        for j, cell in enumerate(self.state["sorting_station"]):
                            if out_product == cell and cell is not None:
                                self.state["sorting_AGV"][i] = cell
                                self.state["sorting_station"][j] = None
                                logger.info(f"id_0035 分拣台 {j} -> 分拣AGV {i} , 产品: {cell}")
                                return

                continue

            # 检查是否满足转运条件 中转站和AGV中满足三个产品相同
            if self.check_sorting_and_transfer(product):
                for j, cell in enumerate(self.state["sorting_AGV"]):
                    if cell is None:
                        for k, empty_cell in enumerate(self.state["transfer_station"]):
                            if empty_cell == product:
                                self.state["transfer_station"][k] = None
                                self.state["sorting_AGV"][j] = product
                                logger.info(f"id_034 中转站 {k} -> 分拣AGV {j} , 产品: {product}")
                                return

            # 需要检查中转站 中满足转运的产品 优先取出该产品 至AGV 再放置剩余产品 再取出分拣台产品
            if self.state["transfer_station"].count(None) <= 1 and out_product is None:
                for j, cell in enumerate(self.state["transfer_station"]):
                    if self.check_all_station(cell):
                        for k, empty_cell in enumerate(self.state["sorting_AGV"]):
                            if empty_cell is None:
                                self.state["transfer_station"][j] = None
                                self.state["sorting_AGV"][k] = cell
                                logger.info(f"id_036 从中转站 {j} -> 分拣AGV {k} , 产品: {cell}")
                                return

            if product == out_product:
                    continue

            # 寻找最佳位置
            best_position = self.find_best_position(product)
            if best_position == -1:
                # 如果未找到合适位置，等待1秒后重试
                logger.info(f"id_045 未找到合适位置 分拣AGV {i} , 产品: {product}")
                await asyncio.sleep(1)
                continue
            else:
                # 移动产品到最佳位置
                self.state["transfer_station"][best_position] = product
                self.state["sorting_AGV"][i] = None
                logger.info(f"id_037 分拣AGV {i} -> 分拣台 {best_position} , 产品: {product}")
                return

    """检查是否满足转运条件"""
    def check_all_station(self, product: str) -> bool:
        # 检查总数量是否满足三个以上
        if self.state["sorting_AGV"].count(product) + self.state["transfer_station"].count(product) + self.state["sorting_station"].count(product) >= 3:
            return True

        return False

    """检查是否满足转运条件"""
    def check_sorting_and_transfer(self, product: str) -> bool:
        # 检查总数量是否满足三个以上
        if self.state["sorting_AGV"].count(product) + self.state["transfer_station"].count(product) >= 3:
            return True

        return False

    """检查中继站满足三个"""
    def check_transfer_station(self) -> bool:
        # 检查总数量是否满足三个以上
        for i, product in enumerate(self.state["transfer_station"]):
            if product is None:
                continue
            if self.state["transfer_station"].count(product) >= 3:
                return True, i

        return False, -1

    """寻找最佳的产品放置位置"""
    def find_best_position(self, product: str) -> int:
        best_position = -1 # 初始化最佳位置为-1, 表示未找到合适位置
        best_score = -1 # 初始化最佳分数为-1, 表示未找到合适位置

        # 评估每个空位的放置价值
        for index, cell in enumerate(self.state["transfer_station"]):
            if cell is None:
                # 计算这个位置的分数，分数越高越适合放置当前产品
                score = self.calculate_position_score(index, product)

                # 如果找到更好的位置，更新最佳位置
                if score > best_score:
                    best_score = score
                    best_position = index

        return best_position

    """计算位置分数，评估放置产品的价值"""
    def calculate_position_score(self, position: int, product: str) -> int:
        score = 0

        # 1. 检查是否可以形成三连（最高权重）
        if position > 0 and position < len(self.state["transfer_station"]) - 1 and \
           self.state["transfer_station"][position - 1] == product and \
           self.state["transfer_station"][position + 1] == product:
            score += 200  # 可以形成三连，大幅加分

        # 2. 检查相邻位置是否有相同产品（次高权重）
        # 左侧相邻
        if position > 0 and self.state["transfer_station"][position - 1] == product:
            score += 100  # 相同产品相邻加分
        # 右侧相邻
        if position < len(self.state["transfer_station"]) - 1 and self.state["transfer_station"][position + 1] == product:
            score += 100  # 相同产品相邻加分

        # 3. 检查附近是否有相同产品集群（中等权重）
        cluster_bonus = self.calculate_cluster_bonus(position, product)
        score += cluster_bonus

        # 4. 检查该位置周围的空位，优先选择有连续空位的位置（便于未来放置）
        empty_space_bonus = self.calculate_empty_space_bonus(position)
        score += empty_space_bonus

        # 5. 基本分：确保空位都有基础分值
        score += 10

        return score

    """计算集群奖励分"""
    def calculate_cluster_bonus(self, position: int, product: str) -> int:
        bonus = 0
        cluster_range = 4  # 检查周围4个位置

        # 计算左侧相同产品数量
        for i in range(1, cluster_range + 1):
            if position - i >= 0 and self.state["transfer_station"][position - i] == product:
                bonus += (cluster_range - i + 1) * 10  # 越近加分越多
            elif position - i >= 0 and self.state["transfer_station"][position - i] is not None:
                break  # 遇到不同产品则停止计数

        # 计算右侧相同产品数量
        for i in range(1, cluster_range + 1):
            if position + i < len(self.state["transfer_station"]) and self.state["transfer_station"][position + i] == product:
                bonus += (cluster_range - i + 1) * 10  # 越近加分越多
            elif position + i < len(self.state["transfer_station"]) and self.state["transfer_station"][position + i] is not None:
                break  # 遇到不同产品则停止计数

        return bonus

    """计算空位奖励分（优先选择有连续空位的位置）"""
    def calculate_empty_space_bonus(self, position: int) -> int:
        bonus = 0

        # 检查左侧连续空位数
        left_empty_count = 0
        for i in range(1, 4):
            if position - i >= 0 and self.state["transfer_station"][position - i] is None:
                left_empty_count += 1
            else:
                break

        # 检查右侧连续空位数
        right_empty_count = 0
        for i in range(1, 4):
            if position + i < len(self.state["transfer_station"]) and self.state["transfer_station"][position + i] is None:
                right_empty_count += 1
            else:
                break

        # 计算连续空位的总长度
        total_empty_length = left_empty_count + right_empty_count + 1
        bonus += total_empty_length * 5  # 每连续一个空位加5分

        return bonus

    """ 获取状态文件路径 """
    def get_file_path(self) -> str:
        """获取状态文件的存储路径"""
        # 在项目根目录下创建一个 data 文件夹用于存储状态文件
        base_dir = os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
        data_dir = os.path.join(base_dir, "data")

        # 如果 data 目录不存在，则创建它
        if not os.path.exists(data_dir):
            os.makedirs(data_dir)

        # 状态文件路径
        state_file = os.path.join(data_dir, "sorting_simulator_state.json")
        return state_file

    """ 保存状态到文件 """
    def save_data(self) -> bool:
        """将当前状态保存到文件

        Returns:
            bool: 保存成功返回True，失败返回False
        """
        try:
            state_file = self.get_file_path()

            # 创建要保存的数据字典，包含状态、配置和保存时间
            save_data = {
                "state": self.state,
                "config": self.config,
                "save_time": datetime.now().isoformat(),
                "version": "1.0"
            }

            # 将数据写入JSON文件
            with open(state_file, 'w', encoding='utf-8') as f:
                json.dump(save_data, f, ensure_ascii=False, indent=2)

            return True
        except Exception as e:
            logger.error(f"id_039 保存分拣模拟系统状态和配置失败: {str(e)}")
            return False

    """ 从文件加载状态 """
    def load_data(self, name: str) -> bool:
        """从文件加载状态

        Returns:
            bool: 加载成功返回True，失败返回False
        """
        try:
            state_file = self.get_file_path()

            # 检查状态文件是否存在
            if not os.path.exists(state_file):
                logger.warning(f"id_040 状态文件 {state_file} 不存在，将使用初始状态")
                return False

            # 从JSON文件读取数据
            with open(state_file, 'r', encoding='utf-8') as f:
                save_data = json.load(f)

            # 恢复状态
            if name == "state":
                self.state = save_data[name]
            elif name == "config":
                self.config = save_data[name]

            # 记录加载信息
            save_time = save_data.get("save_time", "未知时间")
            version = save_data.get("version", "未知版本")
            logger.info(f"id_041 分拣模拟系统状态 {name} 已从 {state_file} 加载，保存时间: {save_time}，版本: {version}")

            return True
        except Exception as e:
            logger.error(f"id_042 加载分拣模拟系统状态 {name} 失败: {str(e)}")
            return False

    """ 获取分拣模拟系统状态 """
    def get_state(self) -> None:
        return {**self.state, **self.config}


# 全局模拟实例
_sorting_simulator_instance = None

"""获取分拣模拟系统实例"""
def get_sorting_simulator() -> AgvSortingSimulator:
    global _sorting_simulator_instance
    if _sorting_simulator_instance is None:
        _sorting_simulator_instance = AgvSortingSimulator()
        # 尝试加载之前保存的状态
        _sorting_simulator_instance.load_data("state")
        # 尝试加载之前保存的配置
        _sorting_simulator_instance.load_data("config")

    return _sorting_simulator_instance
